package cn.sangedon.review.analysis.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.sangedon.review.analysis.domain.StrategyResultQuery;
import cn.sangedon.review.analysis.mapper.StockStrategyMapper;
import cn.sangedon.review.analysis.service.ScheduleService;
import cn.sangedon.review.analysis.service.StockStrategyResultService;
import cn.sangedon.review.analysis.service.StockStrategyService;
import cn.sangedon.review.analysis.strategy.IStrategyFactory;
import cn.sangedon.review.analysis.utils.CheckUtil;
import cn.sangedon.review.common.constant.TypeConstant;
import cn.sangedon.review.common.domain.analysis.StockStrategy;
import cn.sangedon.review.common.domain.analysis.StockStrategyResult;
import cn.sangedon.review.common.domain.bean.TradeDateList;
import cn.sangedon.review.common.domain.data.StockDayInfo;
import cn.sangedon.review.common.domain.data.TradingDate;
import cn.sangedon.review.common.query.data.StockDayInfoQuery;
import cn.sangedon.review.common.service.data.StockDayInfoService;
import cn.sangedon.review.common.service.data.TradingDateService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * @author dongliangqiong
 * @description 针对表【tb_stock_strategy】的数据库操作Service实现
 * @createDate 2022-08-26 18:00:56
 */
@Slf4j
@Service
public class StockStrategyServiceImpl extends ServiceImpl<StockStrategyMapper, StockStrategy> implements StockStrategyService {
    @Autowired
    private ScheduleService scheduleService;

    @Autowired
    private IStrategyFactory strategyFactory;

    @DubboReference
    private TradingDateService tradingDateService;

    @DubboReference
    private StockDayInfoService stockDayInfoService;

    @Autowired
    private StockStrategyResultService strategyResultService;

    @Override
    public List<StockStrategy> listStrategy(Integer status) {
        QueryWrapper<StockStrategy> queryWrapper = new QueryWrapper<>();
        if (status != null) {
            queryWrapper.eq("status", status);
        }
        return this.list(queryWrapper);
    }

    @Override
    public void execStrategy(Long id) {
        StockStrategy strategy = this.getById(id);
        strategyFactory.createStrategy(strategy).execute();
    }

    @Override
    public Map<String, Object> verify(Long id, String time) {
        Map<String, Object> resMap = new HashMap<>();
        StrategyResultQuery strategyResultQuery = new StrategyResultQuery();
        strategyResultQuery.setStrategyId(id);
        if (StringUtils.hasText(time)) {
            time = DateUtil.today();
        }
        strategyResultQuery.setStartTime(time);
        strategyResultQuery.setEndTime(time);
        List<StockStrategyResult> strategyResults = strategyResultService.getStrategyResult(strategyResultQuery);
        if (CollectionUtils.isEmpty(strategyResults)) {
            log.info("未查询到策略选股结果,id:{},time:{}", id, time);
            return resMap;
        }

        TradeDateList tradingDay = tradingDateService.postTradingDay(time, 1);
        List<StockDayInfo> stockDayInfos = stockDayInfoService.getStockDayInfos(tradingDay.current().getTradingDate(), TypeConstant.EQ);
        if (CollectionUtils.isEmpty(stockDayInfos)) {
            log.info("未查询到日交易信息");
            return resMap;
        }

        Map<String, StockDayInfo> dayInfoMap = stockDayInfos.stream().collect(Collectors.toMap(StockDayInfo::getCode, Function.identity()));
        int total = strategyResults.size();
        int passNum = 0;
        for (StockStrategyResult strategyResult : strategyResults) {
            if (dayInfoMap.get(strategyResult.getStockCode()).getChangeRate().signum() > 0) {
                passNum += 1;
            }
        }
        resMap.put("total", total);
        resMap.put("passNum", passNum);
        resMap.put("passRatio", (passNum * 100) / total);
        return resMap;
    }

    @Override
    public Map<String, Object> verifyHistory(Long id, String startTime, String endTime) {
        Map<String, Object> resMap = new HashMap<>();
        StockDayInfoQuery query = new StockDayInfoQuery();
        query.setStartTime(startTime);
        query.setEndTime(endTime);
        List<StockDayInfo> stockDayInfos = stockDayInfoService.getStockDayInfos(query);
        if (CollectionUtils.isEmpty(stockDayInfos)) {
            log.info("未查询到日交易信息");
            return resMap;
        }
        TradeDateList tradeDateList = tradingDateService.betweenTradingDay(startTime, endTime);
        if (tradeDateList == null) {
            log.info("未查询到交易日信息");
            return resMap;
        }

        Map<String, List<StockDayInfo>> stockInfoCodeMap = stockDayInfos.stream().sorted(
            (e1, e2) -> e1.getTradingDate().compareTo(e2.getTradingDate())).collect(Collectors.groupingBy(StockDayInfo::getCode));

        Map<String, Map<String, StockDayInfo>> dateCodeStockInfoMap = new HashMap<>();
        stockDayInfos.stream().forEach(stockInfo -> {
            Map<String, StockDayInfo> codeStockInfoMap = dateCodeStockInfoMap.getOrDefault(stockInfo.getTradingDate(), new HashMap<>());
            codeStockInfoMap.put(stockInfo.getCode(), stockInfo);
            dateCodeStockInfoMap.put(stockInfo.getTradingDate(), codeStockInfoMap);
        });

        Map<String, List<StockDayInfo>> strategyResultMap = new HashMap<>();
        int total = 0;
        int pass = 0;
        for (Entry<String, List<StockDayInfo>> sameStockDayInfoEntry : stockInfoCodeMap.entrySet()) {
            List<StockDayInfo> sameStockDayInfos = sameStockDayInfoEntry.getValue();
            for (int i = 1; i < sameStockDayInfos.size(); i++) {
                StockDayInfo today = sameStockDayInfos.get(i);
                if (DateUtil.parseDateTime(today.getTradingDate()).compareTo(DateUtil.parseDate(endTime)) == 0) {
                    continue;
                }
                StockDayInfo yestoday = sameStockDayInfos.get(i - 1);
                if (!CheckUtil.fallShrinkRed(today, yestoday)) {
                    continue;
                }
                total += 1;
                List<StockDayInfo> dayInfos = strategyResultMap.getOrDefault(today.getTradingDate(), new ArrayList<>());
                dayInfos.add(today);
                strategyResultMap.put(today.getTradingDate(), dayInfos);

                TradingDate postTradingDate = tradeDateList.behind(today.getTradingDate());
                if (postTradingDate == null) {
                    total -= 1;
                    continue;
                }
                Map<String, StockDayInfo> codeInfoMap = dateCodeStockInfoMap.get(postTradingDate.getTradingDate());
                if (codeInfoMap == null) {
                    total -= 1;
                    continue;
                }
                StockDayInfo nextStockInfo = codeInfoMap.get(today.getCode());
                if (nextStockInfo == null) {
                    total -= 1;
                    continue;
                }
                if (nextStockInfo.getChangeRate().signum() >= 0) {
                    pass += 1;
                }
            }
        }
        int passRatio = (pass * 100) / total;
        log.info("{} ~ {} 策略验证结果，total:{}, pass:{}, passRatio:{}", startTime, endTime, total, pass, passRatio);
        resMap.put("total", total);
        resMap.put("pass", pass);
        resMap.put("passRatio", passRatio);
        return resMap;
    }

    private void checkStrategy(List<StockDayInfo> sameStockDayInfos, Map<String, List<StockDayInfo>> strategyResultMap) {

    }
}




